import { Prefab, Node, instantiate, NodePool, Vec3, resources } from "cc";

export class PoolManager {
    private static PoolDict: any = {};
    private static PrefabDict: any = {};

    /**
     * 对象池中获取对应节点
     */
    public static GetNode(path: string, parent: Node, position: Vec3 = Vec3.ZERO, scale: Vec3 = Vec3.ONE): Promise<Node> {
        const segments = path.split(`/`);
        let name = segments[segments.length - 1];

        const GetNodeFunc = (prefab): Node => {
            let node: Node = null;

            if (this.PoolDict.hasOwnProperty(name)) {
                //已有对应的对象池
                let pool = this.PoolDict[name];
                if (pool.size() > 0) {
                    node = pool.get();
                } else {
                    node = instantiate(prefab);
                }
            } else {
                //没有对应对象池，创建他！
                this.PoolDict[name] = new NodePool();
                node = instantiate(prefab);
            }

            node.active = true;
            node.setParent(parent);
            node.setWorldScale(scale);
            node.setPosition(position);
            return node;
        }

        return new Promise((resolve, reject) => {
            if (!this.PrefabDict.hasOwnProperty(name)) {
                resources.load(path, (err: any, prefab: Prefab) => {
                    if (err) {
                        console.error(`Prefab 加载失败：${path}`);
                        reject && reject();
                        return;
                    }

                    this.PrefabDict[name] = prefab;
                    resolve && resolve(GetNodeFunc(prefab));
                })
            } else {
                resolve && resolve(GetNodeFunc(this.PrefabDict[name]));
            }
        });
    }

    /**
     * 向对象池里生成固定数量的 Node
     */
    public static GenerateNodes(path: string, count: number) {
        const segments = path.split(`/`);
        let name = segments[segments.length - 1];

        resources.load(path, (err: any, prefab: Prefab) => {
            if (err) {
                console.error(`Prefab 加载失败：${path}`);
                return;
            }

            this.PrefabDict[name] = prefab;

            //已有对应的对象池
            if (this.PoolDict.hasOwnProperty(name)) {
                let pool = this.PoolDict[name];
                if (pool.size() < count) {
                    let length = count - pool.size();
                    for (let i = 0; i < length; i++)pool.put(instantiate(prefab));
                }
            } else {
                this.PoolDict[name] = new NodePool();
                for (let i = 0; i < count; i++) this.PoolDict[name].put(instantiate(prefab));
            }
        });
    }

    /**
    * 根据预设从对象池中获取对应节点
    */
    public static GetNodeByPrefab(prefab: Prefab, parent: Node) {
        let name = prefab.name;
        this.PrefabDict[name] = prefab;
        let node = null;
        if (this.PoolDict.hasOwnProperty(name)) {
            //已有对应的对象池
            let pool = this.PoolDict[name];
            if (pool.size() > 0) {
                node = pool.get();
            } else {
                node = instantiate(prefab);
            }
        } else {
            //没有对应对象池，创建他！
            this.PoolDict[name] = new NodePool();
            node = instantiate(prefab);
        }

        node.parent = parent;
        node.position = Vec3.ZERO;
        node.active = true;

        return node;
    }

    /**
     * 将对应节点放回对象池中
     */
    public static PutNode(node: Node) {
        if (!node) return;

        let name = node.name;
        let pool = null;
        if (this.PoolDict.hasOwnProperty(name)) {
            pool = this.PoolDict[name];
        } else {
            pool = new NodePool();
            this.PoolDict[name] = pool;
        }

        pool.put(node);
    }

    /**
     * 根据名称，清除对应对象池
     */
    public static ClearPool(name: string) {
        if (this.PoolDict.hasOwnProperty(name)) {
            let pool = this.PoolDict[name];
            pool.clear();
        }
    }
}